package sanduche.play.generators

import java.io.PrintWriter
import java.io.File
import scala.io.Source

object PlayGenerator {
	val playControllersPath="app/controllers/";
	val playControllersPackage="controllers";
	val sanducheControllersPackage="sanduche.controllers"
	def apply(modules: Seq[SanModule]) {
		val routes = Source.fromFile("conf/routes");
		val content = routes.getLines.toList    
		routes.close    
		val inIndex = content.zipWithIndex.find {
			case (line, index) =>
			line.contains("#GENERATED-ROUTES")
		}.map(_._2).get
		
		val endIndex = content.zipWithIndex.find {
			case (line, index) =>
				line.contains("#ENDGENERATED-ROUTES")
		}.map(_._2).get
    
		val contentBefore = content.zipWithIndex.filter{ case(line,index)=>
      
			index<=inIndex
		}.map(_._1)
    
		val contentAfter= content.zipWithIndex.filter{ case(line,index)=>
			index>=endIndex
		}.map(_._1)
    
		val generatedRoutes=modules.flatMap{module=>
			toPlayRoutes(module)
		}
		val pwRoutes =  new PrintWriter(new File("conf/routes"));
		contentBefore.foreach(pwRoutes.println(_))   
		generatedRoutes.foreach(pwRoutes.println(_))
		contentAfter.foreach(pwRoutes.println(_))
		pwRoutes.close()

		modules.foreach(module => {
			val f = new File(playControllersPath ++ playControllerName(module) ++ ".java");
			if (!f.exists()) f.createNewFile();
			val pw = new PrintWriter(f);
			pw.print(toJavaPlayController(module));      
			pw.close();
		});
	}
  
	def playControllerName(module:SanModule)={
		module.name.capitalize++"Controller"
	}
  

    def toPlayRoutes(module:SanModule)={      
      	module.services.map(service => {
      		toPlayRoute(service,module.prefix);
      	});  
    }
      
    def toPlayRoute(service:SanService,prefix:String)={
      	s"""${service.route.method()}	${prefix}${service.route.value()}	$playControllersPackage.${playControllerName(service.moduleParent)}.${service.method.getName()}(${
      		service.urlParams.map(urlParam => { urlParam.paramName ++ ":" ++ urlParam.simpleJavaTypeName }).mkString(", ");
      	})"""    	
     } 
    
    
    def toJavaPlayController(module: SanModule) = {
        s"""
        |package controllers;
        |import vos.*;
        |import play.db.jpa.Transactional;
        |import play.libs.Json;
        |import sanduche.play.shared.SanController;
        |import play.mvc.Http.Request;
        |import play.mvc.Http.Response;
        |import play.mvc.Http.Session;
        |import play.mvc.Result;
        |import models.*;
        |public class ${module.clazz.getSimpleName();} extends SanController {${
          module.services.map(service => {
            toPlayAction(service);
          }).mkString("\n ");
        }
        |}""".stripMargin
    
    }
    
	def toPlayAction(service:SanService)={     
		val call = s"""${service.moduleParent.clazz.getCanonicalName()}.${service.method.getName}(${service.params.map(_.reference).mkString(", ")})""";
      	s"""
      	|	${service.maybeTransactional.map(transactional=>{"@Transactional"++(if(transactional.readOnly())"(readOnly=true)"else"")}).getOrElse("")}
      	|	public static Result ${service.method.getName()}(${service.urlParams.map(_.declaration).mkString(", ");}){
      	|		try{
      	|			${(service.maybeBody.map(_.assignment).
      	  toList  ::: service.maybeRequest.map(_.assignment).
      	  toList :::  service.maybeSession.map(_.assignment).
      	  toList ::: service.maybeResponse.map(_.assignment).toList).mkString("\n|			")}
      	|			${
      		if (service.returns)
      			s"return ok(Json.toJson($call));"
      			else
      				s"$call;return ok();"
      	}
      	|		}catch(Throwable e){return parseError(e);}
      	|	}""".stripMargin
  
	}
    
}